/////////////////////////////////////////////////////
// File Name: mac_r_v1.v
// Author: zeping fan
// mail:   zpfan007@163.com
// Created Time: 2023年06月08日 星期四 08时21分28秒
/////////////////////////////////////////////////////

module mac_r (
//system  interface
input           clk,
input           rst_n,
//MII interface
input           rx_clk,
input           rx_dv,
input   [3:0]   rx_d,
//mac_r to interface_mux
input           data_fifo_rd,
output  [7:0]   data_fifo_dout,
input           ptr_fifo_rd,
output  [15:0]  ptr_fifo_dout,
output          ptr_fifo_empty
);

parameter   DATA_FIFO_DEPTH = 8192;
parameter   FIFO_PTR_WIDTH = $clog2(DATA_FIFO_DEPTH);
parameter   CRC_RESULT  = 32'hc704dd7b;
parameter   MAX_LENGTH  = 1518;
parameter   MIN_LENGTH  = 64;
parameter   MAX_LEN_BIT = 12;

localparam  IDLE        = 3'b001;
localparam  READY       = 3'b010;
localparam  TRANS       = 3'b100;


//控制状态机
reg     [2:0]               cur_state;
reg     [2:0]               nxt_state;

//输入延迟，用于边沿检测和数据缓存
reg                         rx_dv_r1,rx_dv_r2;
reg     [3:0]               rx_d_r;
wire                        rx_dv_pos_edge;

//状态调转控制变量
wire                        sof;    //start of frame  帧开始标志，只能表示有MAC帧
wire                        sfd;    //start frame describe  帧开始符，MAC数据真正输入
wire                        eof;    //end of frame  帧结束标志
wire                        bp;     //back pressuse 当前是否可以存入一个完整的数据帧

//例化模块接口
wire                        data_fifo_wr;
wire    [FIFO_PTR_WIDTH:0]  data_fifo_wr_cnt;
wire    [7:0]               data_fifo_din;

reg                         ptr_fifo_wr;
reg     [15:0]              ptr_fifo_din;
wire                        ptr_fifo_full;

//计数器
reg     [MAX_LEN_BIT-1:0]   byte_cnt;

wire                        length_exceed;    //frame length beyond MAX_LENGTH       
wire                        length_lack;      //frame length shorter than MIN_LENGTH
wire    [31:0]              crc_reg;

//==================输入延迟缓存====================
always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)begin
        rx_dv_r1 <= 1'b0;
        rx_dv_r2 <= 1'b0;
        rx_d_r[3:0] <= 4'b0;
    end
    else begin
        rx_dv_r1 <= rx_dv;
        rx_dv_r2 <= rx_dv_r1;
        rx_d_r[3:0] <= rx_d[3:0];
    end
end

assign  rx_dv_pos_edge = rx_dv_r1 && ~rx_dv_r2;

//================状态跳转控制变量==================
assign  sof = rx_dv_pos_edge && ({rx_d,rx_d_r}==8'h55);

assign  sfd = rx_dv_pos_edge && ({rx_d,rx_d_r}==8'hd5);

assign  eof = ~rx_dv && rx_dv_r1;

assign  bp  = (data_fifo_wr_cnt>DATA_FIFO_DEPTH-MAX_LENGTH) || ptr_fifo_full;

//================三段式状态机======================
always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        cur_state[2:0] <= IDLE;
    else
        cur_state[2:0] <= nxt_state[2:0];
end

always @(*)begin
    case(cur_state)
        IDLE:   nxt_state = ~bp? (sof? READY : sfd? TRANS : IDLE) : IDLE;
        READY:  nxt_state = ({rx_d,rx_d_r}==8'hd5)? TRANS : READY;         //The default vld signal value will not be pulled low by mistake
        TRANS:  nxt_state = (eof || length_exceed)? IDLE : TRANS;
        default:nxt_state = IDLE;
    endcase
end

//==================字节计数器======================
always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        byte_cnt[MAX_LEN_BIT-1:0] <= {MAX_LEN_BIT{1'b0}};
    else if(cur_state[2:0]==IDLE)
        byte_cnt[MAX_LEN_BIT-1:0] <= {MAX_LEN_BIT{1'b0}};
    else if(cur_state[2:0]==TRANS)
        byte_cnt[MAX_LEN_BIT-1:0] <= byte_cnt[MAX_LEN_BIT-1:0] + 1'b1;
end

assign length_exceed = byte_cnt[MAX_LEN_BIT-1:1]>MAX_LENGTH;

assign length_lack   = byte_cnt[MAX_LEN_BIT-1:1]<MIN_LENGTH;


//===============data_fifo数据写入==================
assign  data_fifo_wr = byte_cnt[0] && (cur_state[2:0]==TRANS);

assign  data_fifo_din[7:0] = {rx_d[3:0],rx_d_r[3:0]};

//================ptr_fifo数据写入==================
always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        ptr_fifo_wr <= 1'b0;
    else if((eof || length_exceed) && cur_state[2:0]==TRANS)
        ptr_fifo_wr <= 1'b1;
    else 
        ptr_fifo_wr <= 1'b0;
end

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        ptr_fifo_din[15:0] <= 16'b0;
    else if(eof || length_exceed)begin
        ptr_fifo_din[15] <= (crc_reg[31:0]==CRC_RESULT)? 1'b0 : 1'b1;
        ptr_fifo_din[14] <= (length_exceed || length_lack)? 1'b1 : 1'b0;
        ptr_fifo_din[10:0] <= byte_cnt[MAX_LEN_BIT-1:1];
    end
end
//===================模块例化=======================
crc32 
x_crc32_v1(
    .clk(rx_clk),
    .rstn(rst_n),
    .data(data_fifo_din),
    .init(rx_dv_pos_edge),
    .vld(data_fifo_wr),
    .calc(data_fifo_wr),
    .crc_reg(crc_reg),
    .crc()
);

asyn_fifo#(
    .FIFO_DEPTH(DATA_FIFO_DEPTH),
    .DATA_WIDTH(8),
    .DATA_FLOAT_OUT(1'b1)
)
x_data_fifo(
    .rstn_i(rst_n),
    .wr_clk_i(rx_clk),
    .wr_en_i(data_fifo_wr),
    .wr_data_i(data_fifo_din),
    .wr_full_o(),
    .wr_cnt_o(data_fifo_wr_cnt),
    .rd_clk_i(clk),
    .rd_en_i(data_fifo_rd),
    .rd_data_o(data_fifo_dout),
    .rd_empty_o(),
    .rd_cnt_o()
);

asyn_fifo#(
    .DATA_WIDTH(16),
    .FIFO_DEPTH(32),
    .DATA_FLOAT_OUT(1'b1)
)
x_ptr_fifo(
    .rstn_i(rst_n),
    .wr_clk_i(rx_clk),
    .wr_en_i(ptr_fifo_wr),
    .wr_data_i(ptr_fifo_din),
    .wr_full_o(ptr_fifo_full),
    .wr_cnt_o(),
    .rd_clk_i(clk),
    .rd_en_i(ptr_fifo_rd),
    .rd_data_o(ptr_fifo_dout),
    .rd_empty_o(ptr_fifo_empty),
    .rd_cnt_o()
);

endmodule
   
